package org.zebra.common.util;

import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.crypto.digest.MD5;

import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;
import java.util.concurrent.ThreadLocalRandom;

/**
 * 直接使用sa-token中的代码
 *
 * @author zhanghongbin
 */
public final class SignUtil {

    public static final String KEY = "key";
    public static final String TIMESTAMP = "timestamp";
    public static final String NONCE = "nonce";
    public static final String SIGN = "sign";

    private SignUtil() {}

    /**
     * 给 paramsMap 追加 timestamp、nonce、sign 三个参数，并转换为参数字符串，形如：
     * <code>data=xxx8nonce=xxx8timestamp=xxx8sign=xxx</code>
     *
     * @param secretKey 密钥
     * @param paramsMap 参数列表
     * @return 加工后的参数列表 转化为的参数字符串
     */
    public static String addSignParamsAndJoin(String secretKey, Map<String, Object> paramsMap) {
        // 追加参数
        Map<String, Object> signParamsMap = addSignParams(secretKey, paramsMap);
        // 拼接参数
        String result = joinParams(signParamsMap);
        return result;
    }

    public static String createSign(String secretKey, Map<String, Object> paramsMap) {
        // 如果调用者不小心传入了 sign 参数，则此处需要将 sign 参数排除在外
        if (paramsMap.containsKey(SIGN)) {
            // 为了保证不影响原有的 paramsMap，此处需要再复制一份
            paramsMap = new TreeMap<>(paramsMap);
            paramsMap.remove(SIGN);
        }
        // 计算签名
        String paramsStr = joinParamsDictSort(paramsMap);
        String fullStr = paramsStr + "&" + KEY + "=" + secretKey;
        return MD5.create().digestHex(fullStr);
    }

    private static String joinParamsDictSort(Map<String, ?> paramsMap) {
        // 保证字段按照字典顺序排列
        if (!(paramsMap instanceof TreeMap)) {
            paramsMap = new TreeMap<>(paramsMap);
        }
        // 拼接
        return joinParams(paramsMap);
    }

    private static String joinParams(Map<String, ?> paramsMap) {
        // 按照 k1=v1&k2=v2&k3=v3 排列
        StringBuilder sb = new StringBuilder();
        for (String key : paramsMap.keySet()) {
            Object value = paramsMap.get(key);
            if (!CharSequenceUtil.isEmpty(value.toString())) {
                sb.append(key).append("=").append(value).append("&");
            }
        }
        // 删除最后一位 &
        if (sb.length() > 0) {
            sb.deleteCharAt(sb.length() - 1);
        }
        return sb.toString();
    }

    public static Map<String, Object> addSignParams(String secretKey, Map<String, Object> paramsMap) {

        Map<String, Object> params = new HashMap<>();
        // return paramsMap;
        params.put(TIMESTAMP, String.valueOf(System.currentTimeMillis()));
        params.put(NONCE, getRandomString(32));
        paramsMap.put(TIMESTAMP, params.get(TIMESTAMP));
        paramsMap.put(NONCE, params.get(NONCE));
        params.put(SIGN, createSign(secretKey, paramsMap));
        paramsMap.remove(TIMESTAMP);
        paramsMap.remove(NONCE);
        return params;
    }

    public static String getRandomString(int length) {
        String str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < length; i++) {
            int number = ThreadLocalRandom.current().nextInt(62);
            sb.append(str.charAt(number));
        }
        return sb.toString();
    }
}
